package bma.common.json;

import java.util.Iterator;
import java.util.Map.Entry;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

import bma.common.langutil.core.ExceptionUtil;
import bma.common.langutil.core.Preconditions;
import bma.common.langutil.core.ValueUtil;

public class JsonEditCommand {

	private ArrayNode commands;

	public JsonNode getCommands() {
		return commands;
	}

	public void setCommands(JsonNode commands) {
		Preconditions.checkNotNull(commands);
		if (!(commands instanceof ArrayNode)) {
			throw new IllegalArgumentException("invalid JsonArray (" + commands
					+ ")");
		}
		this.commands = (ArrayNode) commands;
	}

	public void setCommandString(String json) {
		try {
			setCommands(JsonUtil.parse(json));
		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public void execute(JsonEditor ed) {
		Preconditions.checkNotNull(commands);
		Iterator<JsonNode> it = commands.iterator();
		while (it.hasNext()) {
			JsonNode node = it.next();
			String cmd = node.path("command").asText();
			if (ValueUtil.empty(cmd))
				continue;
			if ("set".equals(cmd)) {
				JsonNode data = node.get("data");
				if (data == null)
					continue;
				String path = node.path("path").asText();
				if (ValueUtil.notEmpty(path)) {
					if (data.isValueNode()) {
						ed.setNode(path, data);
					} else {
						ed.push(path);
						setCommand(ed, data);
						ed.pop();
					}
				} else {
					setCommand(ed, node.path("data"));
				}
			} else if ("delete".equals(cmd)) {
				String path = node.path("path").asText();
				if (ValueUtil.notEmpty(path)) {
					ed.removeNode(path);
				}
			}
		}
	}

	protected void setCommand(JsonEditor ed, JsonNode data) {
		if (data.isMissingNode())
			return;
		if (data instanceof ObjectNode) {
			ObjectNode o = (ObjectNode) data;
			Iterator<Entry<String, JsonNode>> it = o.getFields();
			while (it.hasNext()) {
				Entry<String, JsonNode> e = it.next();
				JsonNode v = e.getValue();
				if (v.isValueNode()) {
					ed.setField(e.getKey(), e.getValue());
				} else {
					String path = e.getKey();
					if (v.isObject()) {
						ed.pushObject(path);
					} else {
						ed.pushArray(path);
					}
					setCommand(ed, v);
					ed.pop();
				}
			}
		} else if (data instanceof ArrayNode) {
			ArrayNode a = (ArrayNode) data;
			Iterator<JsonNode> it = a.iterator();
			for (int i = 0; it.hasNext(); i++) {
				JsonNode v = it.next();
				if (v.isValueNode()) {
					ed.setIndex(i, v);
				} else {
					String path = "[" + i + "]";
					if (v.isObject()) {
						ed.pushObject(path);
					} else {
						ed.pushArray(path);
					}
					setCommand(ed, v);
					ed.pop();
				}
			}
		}
	}
}
